#include <iostream>
#include <omp.h> // 包含 OpenMP 头文件
#include <unistd.h> // 包含 sleep 函数，用于演示任务并发

// 定义 task_body 函数
// 打印传入的值和执行该任务的线程 ID
void task_body (int &val) {
  // 增加一点延迟，以便观察任务的并发执行
  // 注意：在实际高性能代码中应避免不必要的 sleep
  usleep(10000); // 休眠 10 毫秒
  #pragma omp critical // 使用 critical section 保护 cout 输出，防止交错
  {
    std::cout << "任务由线程 " << omp_get_thread_num()
              << " 执行，值为: " << val << std::endl;
  }
}

void gen_task (int &x) { // on orphaned task construct reference argument
  // x 在任务创建时被捕获（firstprivate），任务执行时使用的是捕获时的值的副本
  #pragma omp task firstprivate(x)
  task_body (x);
}

void test (int &y, int &z) {
  // 创建并行区域，每个线程有自己的 y 副本 (private(y))
  // z 是共享的 (shared by default)
  #pragma omp parallel private(y)
  {
    // 在进入并行区域时，每个线程的私有 y 未初始化（除非使用 firstprivate 或 copyin）
    // 这里我们根据共享的 z 初始化每个线程的私有 y
    y = z + 2 + omp_get_thread_num(); // 让每个线程的 y 值不同
    #pragma omp critical // 保护输出
    {
        std::cout << "线程 " << omp_get_thread_num() << " 初始化私有变量 y 为: " << y << std::endl;
    }

    gen_task (y); // 传递当前线程的私有 y 的值给任务
    gen_task (z); // 传递共享变量 z 的引用给任务（但 task 中 x 是 firstprivate）

    y++;          // 每个线程修改自己的私有 y
    #pragma omp critical // 保护输出
    {
        std::cout << "线程 " << omp_get_thread_num() << " 将私有变量 y 增加到: " << y << std::endl;
    }
    gen_task (y); // 再次传递当前线程的私有 y 的值给任务

    // 注意：任务可能在并行区域结束之后才执行
  } // 并行区域结束，线程在此同步（隐式屏障）
    // #pragma omp taskwait // 如果需要等待所有子任务完成可以加在这里，但在 parallel 外等待更常见
}

// 主函数
int main() {
  int a = 10;
  int b = 20;

  std::cout << "初始值: a = " << a << ", b = " << b << std::endl;
  std::cout << "正在调用 test 函数..." << std::endl;

  // 设置 OpenMP 线程数（可选，默认为系统核心数）
  omp_set_num_threads(3);

  test(a, b); // 调用 test 函数，a 作为 y 的初始引用，b 作为 z 的初始引用

  // 注意：主线程在 test 函数返回后可能不会等待所有任务完成
  // 如果需要确保所有任务都执行完毕再退出，需要在 test 函数内部或外部使用 taskwait
  // 但在这个例子中，并行区域结束时有一个隐式屏障，
  // 而任务是在并行区域内创建的，通常会在并行区域结束前或结束后不久执行完毕。

  std::cout << "Test 函数执行完毕." << std::endl;
  std::cout << "最终值: a = " << a << ", b = " << b << std::endl; // a 的值不会被 test 中的私有 y 修改

  return 0;
}
